package com.ruoyi.project.meal.controller;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.ijpay.core.enums.SignType;
import com.ijpay.core.enums.TradeType;
import com.ijpay.core.kit.HttpKit;
import com.ijpay.core.kit.IpKit;
import com.ijpay.core.kit.WxPayKit;
import com.ijpay.wxpay.WxPayApi;
import com.ijpay.wxpay.WxPayApiConfig;
import com.ijpay.wxpay.WxPayApiConfigKit;
import com.ijpay.wxpay.model.UnifiedOrderModel;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.aspectj.lang.annotation.Log;
import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.page.TableDataInfo;
import com.ruoyi.project.meal.domain.Meal;
import com.ruoyi.project.meal.service.IMealService;
import com.ruoyi.project.mealOrde.domain.MealOrder;
import com.ruoyi.project.mealOrde.service.IMealOrderService;
import com.ruoyi.project.pay.domain.PayConfig;
import com.ruoyi.project.pay.service.IPayConfigService;
import com.ruoyi.project.record.domain.ScoreRecord;
import com.ruoyi.project.record.service.IScoreRecordService;
import com.ruoyi.project.system.domain.SysUser;
import com.ruoyi.project.system.service.ISysConfigService;
import com.ruoyi.project.system.service.ISysUserService;
import com.ruoyi.tools.pay.controller.AbstractWxPayApiController;
import com.ruoyi.tools.pay.domain.WxPayBean;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 充值套餐Controller
 * 
 * @author wyh
 * @date 2024-08-14
 */
@Controller
@RequestMapping("/meal/meal/pay")
public class MealPayController extends AbstractWxPayApiController
{
    @Autowired
    private IMealService mealService;

    @Autowired
    private ISysUserService userService;

    @Autowired
    private IMealOrderService mealOrderService;

    @Autowired
    private ISysConfigService sysConfigService;

    @Autowired
    private IScoreRecordService scoreRecordService;

    private final Logger log = LoggerFactory.getLogger(this.getClass());

    @Autowired
    WxPayBean wxPayBean;

    private String notifyUrl;
    private String refundNotifyUrl;
    private static final String USER_PAYING = "USERPAYING";

    @Autowired
    private IPayConfigService payConfigService;

    /**
     * 读取数据库支付配置
     * @return
     */
    @Override
    public WxPayApiConfig getApiConfig() {
        WxPayApiConfig apiConfig;

        PayConfig payConfig = new PayConfig();
        payConfig.setName("wechatPay");
        List<PayConfig> payConfigs = payConfigService.selectPayConfigList(payConfig);
        PayConfig pConfig = payConfigs.get(0);


        try {
            apiConfig = WxPayApiConfigKit.getApiConfig(pConfig.getAppid());
        } catch (Exception e) {
            apiConfig = WxPayApiConfig.builder()
                    .appId(pConfig.getAppid())
                    .mchId(pConfig.getMchId())
                    .partnerKey(pConfig.getCertPassword())
                    .certPath(pConfig.getCertPath())
                    .domain(pConfig.getNotifyPayDomain())
                    .build();
        }
        // 微信支付回调地址
        notifyUrl = apiConfig.getDomain().concat("/meal/meal/pay/payNotify");
        // 微信退款回调地址
        refundNotifyUrl = apiConfig.getDomain().concat("/meal/meal/pay/refundNotify");
        return apiConfig;
    }

    /**
     * 微信小程序支付
     */
    @Log(title = "套餐支付", businessType = BusinessType.INSERT)
    @RequestMapping(value = "/payMeal", method = {RequestMethod.POST, RequestMethod.GET})
    @ResponseBody
    public AjaxResult payMeal(HttpServletRequest request,@RequestBody Meal meal) {
        Long userId = SecurityUtils.getUserId();
        SysUser sysUser = userService.selectUserById(userId);

        //校验套餐
        Long mealId = meal.getId();
        Meal meal1 = mealService.selectMealById(mealId);
        if(ObjectUtils.isEmpty(meal1)){
            return AjaxResult.error("套餐不存在");
        }

        //校验openid
        String openId = sysUser.getOpenId();
        if(StringUtils.isBlank(openId)){
            return AjaxResult.error("请先授权登录");
        }

        String ip = IpKit.getRealIp(request);
        if (StrUtil.isBlank(ip)) {
            ip = "127.0.0.1";
        }

        //读取套餐支付金额
        String outTradeNo = WxPayKit.generateStr();
        //生成订单
        MealOrder mealOrder = new MealOrder();
        mealOrder.setOutTradeNo(outTradeNo);
        mealOrder.setStatus("待支付");
        mealOrder.setTotalAmount(meal1.getPrice());
        mealOrder.setUserId(userId);
        mealOrder.setRemark(meal1.getName());
        mealOrderService.insertMealOrder(mealOrder);


        WxPayApiConfig wxPayApiConfig = getApiConfig();

        Map<String, String> params = UnifiedOrderModel
                .builder()
                .appid(wxPayApiConfig.getAppId())
                .mch_id(wxPayApiConfig.getMchId())
                .nonce_str(WxPayKit.generateStr())
                .body("信息服务")
                .attach("信息服务")
                .out_trade_no(outTradeNo)
                .total_fee("1")
                .spbill_create_ip(ip)
                .notify_url(notifyUrl)
                .trade_type(TradeType.JSAPI.getTradeType())
                .openid(openId)
                .build()
                .createSign(wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256);

        String xmlResult = WxPayApi.pushOrder(false, params);

        log.info(xmlResult);
        Map<String, String> result = WxPayKit.xmlToMap(xmlResult);

        String returnCode = result.get("return_code");
        String returnMsg = result.get("return_msg");
        if (!WxPayKit.codeIsOk(returnCode)) {
            return AjaxResult.error(returnMsg);
        }
        String resultCode = result.get("result_code");
        if (!WxPayKit.codeIsOk(resultCode)) {
            return AjaxResult.error(returnMsg);
        }
        // 以下字段在 return_code 和 result_code 都为 SUCCESS 的时候有返回
        String prepayId = result.get("prepay_id");
        Map<String, String> packageParams = WxPayKit.miniAppPrepayIdCreateSign(wxPayApiConfig.getAppId(), prepayId,
                wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256);
        String jsonStr = JSON.toJSONString(packageParams);
        log.info("小程序支付的参数:" + jsonStr);
        return AjaxResult.success(jsonStr);
    }


    /**
     * 异步通知
     * 这里面可以写判断支付成功之后的及具体业务需求
     */
    @RequestMapping(value = "/payNotify", method = {RequestMethod.POST, RequestMethod.GET})
    @ResponseBody
    public String payNotify(HttpServletRequest request) {
        System.out.println("支付回调进入J++、");
        String xmlMsg = HttpKit.readData(request);
        log.info("支付通知=" + xmlMsg);
        Map<String, String> params = WxPayKit.xmlToMap(xmlMsg);

        String returnCode = params.get("return_code");

        //通过支付订单号处理业务
        String transaction_id = params.get("transaction_id");
        log.info("支付订单号:"+transaction_id);

        String outTradeNo = params.get("out_trade_no");
        // 注意重复通知的情况，同一订单号可能收到多次通知，请注意一定先判断订单状态
        // 注意此处签名方式需与统一下单的签名类型一致
        if (WxPayKit.verifyNotify(params, getApiConfig().getPartnerKey(), SignType.HMACSHA256)) {
            if (WxPayKit.codeIsOk(returnCode)) {
                // 更新订单信息
                MealOrder mealOrder = mealOrderService.selectMealOrderByOutTradeNo(outTradeNo);
                if(ObjectUtils.isNotEmpty(mealOrder) && "待支付".equals(mealOrder.getStatus())){
                    mealOrder.setTransactionId(transaction_id);
                    mealOrder.setStatus("已付款");
                    mealOrderService.updateMealOrder(mealOrder);

                    //校验用户是否有上级
                    SysUser sysUser = userService.selectUserById(mealOrder.getUserId());
                    Long inviterId = sysUser.getInviterId();
                    if(inviterId!=null && inviterId>0){

                        System.out.println("充值返利进入");

                        //订单返利 给自己
                        String own = sysConfigService.selectConfigByKey("order.rebate.ratio.own");
                        BigDecimal ownRate = new BigDecimal(own);
                        BigDecimal ownScore = ownRate.multiply(mealOrder.getTotalAmount());

                        // 取整，这里使用四舍五入模式，你也可以根据需要选择其他的 RoundingMode
                        BigDecimal roundedOwnScore = ownScore.setScale(0, RoundingMode.HALF_UP);

                        // 转换为 long 类型
                        long ownScoreResult = roundedOwnScore.longValueExact();

                        //更新用户信息
                        Long score = sysUser.getScore();
                        score+=ownScoreResult;
                        sysUser.setScore(score);//新积分

                        BigDecimal balance = sysUser.getBalance();
                        balance = balance.add(mealOrder.getTotalAmount());
                        sysUser.setBalance(balance);//新余额

                        userService.updateUser2(sysUser);

                        //生成返利记录
                        ScoreRecord scoreRecord = new ScoreRecord();
                        scoreRecord.setUserId(mealOrder.getUserId());
                        scoreRecord.setType("充值返积分");
                        scoreRecord.setOutTradeNo(outTradeNo);
                        scoreRecord.setScore(ownScoreResult);
                        scoreRecordService.insertScoreRecord(scoreRecord);

                        //订单返利 给上级
                        String shangji = sysConfigService.selectConfigByKey("order.rebate.ratio");
                        BigDecimal shangjiRate = new BigDecimal(shangji);
                        BigDecimal shangjiScore = shangjiRate.multiply(mealOrder.getTotalAmount());

                        // 取整，这里使用四舍五入模式，你也可以根据需要选择其他的 RoundingMode
                        BigDecimal roundedScore = shangjiScore.setScale(0, RoundingMode.HALF_UP);

                        // 转换为 long 类型
                        long shangjiScoreResult = roundedScore.longValueExact();

                        SysUser sysUser1 = userService.selectUserById(inviterId);
                        Long score1 = sysUser1.getScore();
                        score1+=shangjiScoreResult;
                        sysUser1.setScore(score1);
                        userService.updateUser2(sysUser1);

                        //生成返利记录
                        ScoreRecord scoreRecord2 = new ScoreRecord();
                        scoreRecord2.setUserId(inviterId);
                        scoreRecord2.setFromUserId(mealOrder.getUserId());
                        scoreRecord2.setType("下级充值返积分");
                        scoreRecord2.setOutTradeNo(outTradeNo);
                        scoreRecord2.setScore(shangjiScoreResult);
                        scoreRecordService.insertScoreRecord(scoreRecord2);

                    }


                }

                // 发送通知等
                Map<String, String> xml = new HashMap<String, String>(2);
                xml.put("return_code", "SUCCESS");
                xml.put("return_msg", "OK");
                return WxPayKit.toXml(xml);
            }
        }
        return null;
    }
}
